package io.mvvm.ws.chain;

import io.mvvm.ws.WebSocketChannelHolder;
import io.mvvm.ws.entity.RequestInfo;
import io.mvvm.ws.entity.ResponseInfo;
import io.mvvm.ws.enumerate.ChainMessageTypeEnum;
import io.mvvm.ws.exception.NoMessageHandlerException;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @program: Netty
 * @description: 责任链管理
 * @author: 潘
 * @create: 2021-04-28 19:53
 **/
@Component
public final class MessageHandlerChain {

    private final static Logger logger = LoggerFactory.getLogger(MessageHandlerChain.class);

    private MessageHandler firstHandler;

    private MessageHandler lastHandler;

    @Resource
    private SubscribeMessageHandler subscribeMessageHandler;

    /**
     * 向前添加处理器
     *
     * @param handler
     * @return
     */
    public MessageHandlerChain addHeadHandler(MessageHandler handler) {
        if (null == handler) {
            return this;
        }

        if (hasHandler(this.firstHandler, handler)) {
            return this;
        }

        if (null != this.firstHandler) {
            handler.setNext(this.firstHandler);
            if (null == this.lastHandler) {
                this.lastHandler = this.firstHandler;
            }
        }

        this.firstHandler = handler;

        return this;
    }

    /**
     * 向后添加处理器
     *
     * @param handler
     * @return
     */
    public MessageHandlerChain addLastHandler(MessageHandler handler) {
        if (null == handler) {
            return this;
        }

        if (hasHandler(this.firstHandler, handler)) {
            return this;
        }

        if (null == this.firstHandler) {
            return addHeadHandler(handler);
        }

        if (null != this.lastHandler) {
            this.lastHandler.setNext(handler);
        } else {
            this.firstHandler.setNext(handler);
        }

        this.lastHandler = handler;
        this.lastHandler.setNext(null);

        return this;
    }

    /**
     * 初始化处理器
     *
     * @return
     */
    public MessageHandlerChain init() {
        this.reset();
        addLastHandler(subscribeMessageHandler);
        return this;
    }

    /**
     * 重置处理链
     *
     * @return
     */
    public MessageHandlerChain reset() {
        this.firstHandler = null;
        this.lastHandler = null;
        return this;
    }

    /**
     * 处理器
     *
     * @param request 请求参数
     * @param ctx     Channel 上下文信息
     * @return 响应实体
     */
    public ResponseInfo start(RequestInfo request, ChannelHandlerContext ctx) {
        String uid = request.getUserId();
        String action = request.getAction();

        // 验证用户是否注册过通道，如果没有注册，则为用户注册一个新的通道
        if (!WebSocketChannelHolder.isRegister(uid)) {
            logger.info("用户 {} 未注册通道", uid);
            WebSocketChannelHolder.addChannel(uid, ctx.channel());
        }

        // 验证用户是否请求的为订阅消息，如果是订阅消息，则刷新用户通道
        if (ChainMessageTypeEnum.SUBSCRIBE.getAction().equals(action)) {
            if (WebSocketChannelHolder.isRegister(uid)) {
                logger.info("刷新用户 {} 的通道", uid);
                WebSocketChannelHolder.refreshChannel(uid, ctx.channel());
            }
        }

        if (null != this.firstHandler) {
            return this.firstHandler.start(request, ctx);
        }

        // 关闭通道
        ctx.channel().close();
        logger.error("未找到可执行处理器");
        throw new NoMessageHandlerException("未找到处理器", request);
    }


    /**
     * 当前处理器是否已存在
     *
     * @param currentHandler 当前处理器
     * @param newHandler     新处理器
     * @return
     */
    public boolean hasHandler(MessageHandler currentHandler, final MessageHandler newHandler) {
        if (null == currentHandler) {
            return false;
        }

        if (currentHandler.equals(newHandler)) {
            return true;
        }

        if (null == currentHandler.getNext()) {
            return false;
        }

        return hasHandler(currentHandler.getNext(), newHandler);
    }
}
